package com.faxsun.core.readonly.service.impl;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Set;

import mblog.core.persist.dao.ProductRefDao;
import mblog.core.persist.dao.TagDao;
import mblog.core.pojos.Product;
import mblog.core.utils.BeanMapUtils;

import org.apache.http.client.ClientProtocolException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.faxsun.core.persist.entity.CategoryTagRefPO;
import com.faxsun.core.persist.entity.ProductRefPO;
import com.faxsun.core.persist.entity.TagPO;
import com.faxsun.core.pojos.enums.TagType;
import com.faxsun.core.readonly.dao.ProductDao;
import com.faxsun.core.readonly.entity.ProductRO;
import com.faxsun.core.readonly.service.ProductShopService;
import com.faxsun.http.HttpInvoker;

public class ProductShopServiceImpl implements ProductShopService {

	private static final Logger LOG = LoggerFactory
			.getLogger(ProductShopServiceImpl.class);

	// 此处xml手动注入，以确保sessionFactory使用的是商城的数据库
	ProductDao productDao;

	static final String[] IGNORE = { "Root", "Primary Nav", "test", "夺宝", "母婴",
			"首页", "健康" };
	static final List<String> ignoredList = new ArrayList<String>();

	@Autowired
	ProductRefDao productRefDao;

	@Autowired
	TagDao tagDao;

	@Value("${faxsun.api.shop.url}")
	String apiUrl;

	@Value("${faxsun.api.shop.syncUrl}")
	String isUpdateUrl;

	ObjectMapper mapper = new ObjectMapper();

	public ProductShopServiceImpl() {
		ignoredList.addAll(Arrays.asList(IGNORE));
	}

	@Override
	@Transactional(value = "shopTxManager")
	public List<ProductRO> list() {
		// return productDao.list();
		return null;
	}

	@Transactional
	public void syncCategories() {
		if (!this.apiUrl.endsWith("/")) {
			this.apiUrl += "/";
		}
		String listCategoriesUrl = this.apiUrl + "catalog/categories";

		try {
			String response = HttpInvoker.get(listCategoriesUrl);
			JsonNode tree = mapper.readTree(response);

			JsonNode categories = tree.get("category");
			Iterator<JsonNode> it = categories.iterator();
			while (it.hasNext()) {
				JsonNode node = it.next();
				Long id = node.get("id").asLong();
				String name = node.get("name").asText();
				// System.out.println(id+","+name);
				// 名字在忽略列表中
				if (ignoredList.contains(name)) {
					continue;
				}

				// 检查是否已存在
				TagPO tagPO = tagDao.getByName(name);
				if (tagPO == null) {
					tagPO = new TagPO();
				} else {
					continue;
				}

				// 保存category id，用于以后同步关联分类标签
				tagPO.setName(name);
				tagPO.setEnumType(TagType.CATEGORY);
				CategoryTagRefPO categoryRef = new CategoryTagRefPO();
				categoryRef.setCid(id);
				tagPO.setCategoryRef(categoryRef);
				tagDao.save(tagPO);
			}
		} catch (Exception e) {
			LOG.error("sync categories error", e);
		}
	}

	/**
	 * 同步产品
	 */
	@Override
	@Transactional
	public List<Product> syncProduct() {
		this.syncCategories();
		List<Product> productList = new ArrayList<Product>();
		Long maxId = productRefDao.getMaxProductId();
		// 对已存在的商品进行价格同步
		syncExistedPrice();

		// 获取电商中未同步的商品
		List<ProductRO> productsFromShop = listShopProduct(maxId);
		// 同步新产品
		syncNewProduct(productsFromShop);

		return productList;
	}

	/**
	 * 根据电商api reponse，填充资讯所需信息
	 * 
	 * @param productRefPO
	 * @param tree
	 */
	private void fillProduct(ProductRefPO productRefPO, JsonNode tree) {

		// 读取商品ID和name
		productRefPO.setProductId(tree.get("id").asLong());
		String productName = tree.get("name").asText();
		productRefPO.setName(productName);

		productRefPO.setPrice(new BigDecimal(tree.get("displayedTotalPrice")
				.get("amount").asText()));

		// 图片处理
		JsonNode mediaNode = tree.get("primaryMedia");
		if (mediaNode != null) {
			// 产品主图
			String medias = mediaNode.get("url").asText();
			// 其他产品图片
			JsonNode mediasNodes = tree.get("mediaItems");
			if (mediasNodes != null) {
				int size = mediasNodes.size();
				for (int i = 0; i < size; i++) {
					String mediaUrl = mediasNodes.get(i).get("url").asText();
					mediaUrl = removeProtocl(mediaUrl);
					medias += "||" + mediaUrl;
				}
			}
			productRefPO.setDefaultImageUrl(medias);
		}

		// 获取产品上架状态
		setProductStatus(productRefPO, tree);
	}

	/**
	 * 同步已有产品的价格和Url、主图和上架状态
	 */
	@Transactional
	private void syncExistedPrice() {
		List<ProductRefPO> allProducts = this.productRefDao.list();
		for (ProductRefPO product : allProducts) {
			if ("true".equals(this.isUpdateUrl)) {
				LOG.debug("sync url");
				ProductRO productRO = productDao.get(product.getProductId());
				if (productRO == null) {
					LOG.error("[Product Inconsistence]ProductId="
							+ product.getProductId()
							+ " dose not exist in Axolotl");
					continue;
				}
				if (!productRO.getUrl().equals(product.getUrl())) {
					// 更新URL
					product.setUrl(productRO.getUrl());
				}
			}
			// send request to /catalog/product/{id} to get product details
			if (!this.apiUrl.endsWith("/")) {
				this.apiUrl += "/";
			}
			String listProductUrl = this.apiUrl + "catalog/product/"
					+ product.getProductId();
			LOG.info(listProductUrl);

			try {
				String response = HttpInvoker.get(listProductUrl);

				LOG.info(response);

				JsonNode tree = mapper.readTree(response);

				JsonNode statusCode = tree.get("httpStatusCode");
				if (statusCode != null) {
					continue;
				}

				// 电商对价格取整，此处取整后存储
				BigDecimal price = new BigDecimal(tree
						.get("displayedTotalPrice").get("amount").asText());
				price = price.setScale(0, RoundingMode.UP);
				if (price.compareTo(product.getPrice()) != 0) {
					product.setPrice(price);
				}

				JsonNode mediaNode = tree.get("primaryMedia");
				if (mediaNode != null) {

					// 产品主图
					String medias = mediaNode.get("url").asText();
					if (StringUtils.isEmpty(product.getDefaultImageUrl())
							|| !product.getDefaultImageUrl().startsWith(medias)) {
						// 图片不存在或者主图发生改变[所有图片路径不是以medias开头]
						// 其他产品图片
						JsonNode mediasNodes = tree.get("mediaItems");
						if (mediasNodes != null) {
							int size = mediasNodes.size();
							for (int i = 0; i < size; i++) {
								medias += "||"
										+ mediasNodes.get(i).get("url")
												.asText();
							}
						}
						product.setDefaultImageUrl(medias);
					}
				}

				if (product.getDefaultImageUrl() != null
						&& product.getDefaultImageUrl().startsWith("http:")) {
					String imageUrls = product.getDefaultImageUrl();
					String[] imageUrlArray = imageUrls.split("\\|\\|");
					StringBuffer sb = new StringBuffer();
					for (String url : imageUrlArray) {
						// 移除协议
						url = removeProtocl(url);
						sb.append(url);
						sb.append("||");
					}
					sb.delete(sb.length() - 2, sb.length());
					product.setDefaultImageUrl(sb.toString());
				}

				syncVideoInfo(product, tree);
				// 获取产品上架状态
				setProductStatus(product, tree);
				productRefDao.save(product);

			} catch (ClientProtocolException e) {
				e.printStackTrace();
				LOG.error("sync error", e);
				throw new RuntimeException(e.getMessage());
			} catch (IOException e) {
				e.printStackTrace();
				LOG.error("sync error", e);
				throw new RuntimeException(e.getMessage());
			}
		}

	}

	/**
	 *  从范客生活商城读取未同步的产品列表
	 * 
	 * @param maxId
	 * @return
	 */
	@Transactional(value = "shopTxManager", propagation = Propagation.REQUIRES_NEW)
	private List<ProductRO> listShopProduct(long maxId) {
		List<ProductRO> productsFromShop = productDao.list(maxId);
		return productsFromShop;
	}

	public ProductDao getProductDao() {
		return productDao;
	}

	public void setProductDao(ProductDao productDao) {
		this.productDao = productDao;
	}

	/**
	 * 移除协议，对于包含8081和8080的端口号，替换为8443，用于本地测试
	 * 
	 * @param mediaUrl
	 * @return
	 */
	private String removeProtocl(String mediaUrl) {
		// 移除协议
		if (mediaUrl.startsWith("http:") || mediaUrl.startsWith("https:")) {
			mediaUrl = mediaUrl.substring(mediaUrl.indexOf("//"));
			// if (mediaUrl.contains("8081") || mediaUrl.contains("8080")) {
			// mediaUrl = mediaUrl.replace("8081", "8443");
			// mediaUrl = mediaUrl.replace("8080", "8443");
			// }
		}
		return mediaUrl;
	}

	/**
	 * 根据API返回结果，设置产品状态
	 * 
	 * @param product
	 * @param tree
	 */
	private void setProductStatus(ProductRefPO product, JsonNode tree) {
		if (tree.get("active") != null) {
			// 获取产品上架状态
			boolean isActive = tree.get("active").asBoolean();
			if (isActive) {
				product.setIsFaxsun(1);
			} else {
				product.setIsFaxsun(0);
			}
		}
	}

	/**
	 * 同步电商的新产品
	 * 
	 * @param productsFromShop
	 */
	@Transactional
	private void syncNewProduct(List<ProductRO> productsFromShop) {

		// 遍历未同步商品
		for (ProductRO productFromShop : productsFromShop) {
			ProductRefPO productRefPO = BeanMapUtils.copy(productFromShop);

			// send request to /catalog/product/{id} to get product details
			if (!this.apiUrl.endsWith("/")) {
				this.apiUrl += "/";
			}
			String listProductUrl = this.apiUrl + "catalog/product/"
					+ productFromShop.getId();

			try {
				String response = HttpInvoker.get(listProductUrl);

				LOG.info(response);

				JsonNode tree = mapper.readTree(response);

				// 访问API出错，跳过该商品
				JsonNode statusCode = tree.get("httpStatusCode");
				if (statusCode != null) {
					continue;
				}

				// 验证产品tag name不存在
				String productName = tree.get("name").asText();
				TagPO tagPOVerify = tagDao.getByName(productName);
				if (tagPOVerify != null && tagPOVerify.getId() > 0L) {
					// 存在，则跳过
					continue;
				}

				// 填充保存的内容
				fillProduct(productRefPO, tree);
				productRefDao.save(productRefPO);

				TagPO tagPO = new TagPO();
				tagPO.setEnumType(TagType.PRODUCT);
				tagPO.setProductRef(productRefPO);
				tagPO.setName(productRefPO.getName());

				syncVideoInfo(tagPO, tree);

				// 产品所属分类
				Set<TagPO> categoriesSet = tagPO.getTagsCategorySet();
				// 获取product tag所属的category tag
				String categoriesUrl = this.apiUrl + "catalog/product/"
						+ productRefPO.getProductId() + "/categories";

				String categoriesResponseString = HttpInvoker
						.get(categoriesUrl);

				JsonNode parentCategoriesTree = mapper
						.readTree(categoriesResponseString);
				JsonNode categories = parentCategoriesTree.get("category");
				Iterator<JsonNode> it = categories.iterator();
				while (it.hasNext()) {
					JsonNode node = it.next();
					// Long id=node.get("id").asLong();
					String name = node.get("name").asText();
					if (ignoredList.contains(name)) {
						continue;
					}
					TagPO categoryTag = tagDao.getByName(name);
					categoriesSet.add(categoryTag);
				}

				if (categoriesSet.size() == 0) {
					// 所属分类全在忽略列表中，则跳过该商品
					continue;
				}
				tagPO.setTagsCategorySet(categoriesSet);

				// 产品在电商无图片,
				if (StringUtils.isEmpty(tagPO.getProductRef()
						.getDefaultImageUrl())) {
					// FIXME: use constants instead of magic number
					tagPO.setIsDeleted(1);
				}
				tagDao.save(tagPO);

			} catch (ClientProtocolException e) {
				e.printStackTrace();
				LOG.error("sync error", e);
				throw new RuntimeException(e.getMessage());
			} catch (IOException e) {
				e.printStackTrace();
				LOG.error("sync error", e);
				throw new RuntimeException(e.getMessage());
			}
		}
	}

	private void syncVideoInfo(ProductRefPO productRefPO, JsonNode tree) {
		TagPO tagPO = tagDao.findByProductRefId(productRefPO.getId());
		if (tagPO != null) {
			syncVideoInfo(tagPO, tree);
			tagDao.update(tagPO);
		}
	}

	/**
	 * 同步视频信息
	 * 
	 * @param tagPO
	 *            tag实体
	 * @param tree
	 *            电商api返回的json信息. 格式如下：<br>
	 *            <code>
	 *   {<br>
	 *    ...<br>
	 *    "productAttributes":{<br>
	 *      ...<br>
	 *    	"attributeName":"video",<br>
	 *    	"attributeValue":"url",<br>
	 *       ...<br>
	 *       }<br>
	 *       ...<br>
	 *    }<br>
	 *       </code>
	 */
	private boolean syncVideoInfo(TagPO tagPO, JsonNode tree) {

		JsonNode productAttributeNode = tree.get("productAttributes");
		if (productAttributeNode != null) {
			Iterator<JsonNode> productAttributes = productAttributeNode
					.iterator();
			while (productAttributes.hasNext()) {
				JsonNode productAttribute = productAttributes.next();
				JsonNode attribute = productAttribute.get("attributeName");
				if (attribute != null && "video".equals(attribute.asText())) {
					// video 属性,管理端保证仅有一个video
					String videoUrl = productAttribute.get("attributeValue")
							.asText();
					if (!StringUtils.isEmpty(videoUrl)) {
						tagPO.setVideoUrl(videoUrl);
					} else {
						tagPO.setVideoUrl(null);
					}
					return true;
				}

			}
		}
		return false;
	}
}
